/* 
 * File:   mandataire.c
 *
 */
#include <arpa/inet.h>

#include <netdb.h>
#include <netinet/in.h>
#include <unistd.h>
#include <stdio.h>

#include <stdlib.h>
#include <string.h>
#include <malloc.h>

#define MAX_LINE 100
// 3 caractères pour les codes ASCII 'cr', 'lf' et '\0'
#define LINE_ARRAY_SIZE (MAX_LINE+3)
#define MAX_LIST 10
#define MAX_CONN 5  //Definition du maximum de connexion
#define NB_AUTH 3   //Definition de combien de machine sont autorise

struct record{
	
};


struct paquet{
	int		type;
    struct	sockaddr_in sourceAddress;
	struct	sockaddr_in destinationAddress;
    int 	bloc;
	int		PF;
	int 	session;
	int		qos;
	char	data[LINE_ARRAY_SIZE];
};


int init_ecoute(unsigned short int listenPort);
int init_liste();

//Pointeur de tête de liste circulaire
struct record* head;
//Pointeur de queue de liste circulaire
struct record* queue;


//*****************************************
//Début du Main
//*****************************************
int main(){

int listenSocket, serverSocket, server_lineCapacity, i;
socklen_t clientAddressLength;
int nbAttente, etatReception, etatVidageListe;
struct sockaddr_in sourceAddress, destinationAddress;
char buf[LINE_ARRAY_SIZE], *buffServer, ack[2];
unsigned short int serverPort;
struct hostent *hostInfo;
int nbConn = 0; 

listenSocket = init_ecoute(15000);
server_lineCapacity = 50;
buffServer = (char *)malloc(server_lineCapacity*sizeof(char));

nbAttente = init_liste();
etatReception = 1;
etatVidageListe = 0;

while(strcmp(buf, "quit")) {

	if(etatReception == 1){
		clientAddressLength = sizeof(clientAddress);
		
		// Mise à zéro du tampon de façon à connaître le délimiteur
		// de fin de chaîne.
		memset(buf, 0x0, LINE_ARRAY_SIZE);
		printf(" Apres 0 --- %d\n",strlen(buf));
		
		if (recvfrom(listenSocket, buf, LINE_ARRAY_SIZE, 0,(struct sockaddr *) &clientAddress,&clientAddressLength) < 0) {
			printf("  Probleme d'entree/sortie.");
			exit(1);
		}

		// Affichage de l'adresse IP du client.
		printf(" De %s", inet_ntoa(clientAddress.sin_addr));

		// Affichage du numéro de port du client.
		printf(":%d\n", ntohs(clientAddress.sin_port));

		// Affichage de la ligne reçue
		printf("  Recu: %s\n", buf);
		strcpy(head->buff, buf);
		nbAttente++;
		head = head->suivant;
	}
	
	//Envoie une partie des informations selon la capacité du serveur
	if(strlen(queue->buff)>server_lineCapacity){
		//printf(" Apres 4\n");
		strncpy(buffServer,queue->buff,server_lineCapacity);
		printf(" Apres 5  --- %s\n",buffServer);
		memset(buf, 0x0, LINE_ARRAY_SIZE);
		strncpy(buf, queue->buff+server_lineCapacity,(strlen(queue->buff)-server_lineCapacity));
		printf(" Apres 6 --- %s\n",buf);
		memset(queue->buff, 0x0, LINE_ARRAY_SIZE);
		printf(" Apres 7\n");
		strcpy(queue->buff, buf);
		printf(" Apres 8 --- %d\n",strlen(queue->buff));
		printf(" Apres 9 --- %f\n",((float)nbAttente/(float)MAX_LIST));
	}else{
		printf(" Apres 4\n");
		strncpy(buffServer,queue->buff,server_lineCapacity);
		printf(" Apres 5 --- %s\n",buffServer);
		printf(" Apres 8 --- %d\n",strlen(queue->buff));
		memset(queue->buff, 0x0, LINE_ARRAY_SIZE);
		queue= queue->suivant;
		nbAttente--;
		printf(" Apres 9 ---  %f\n",((float)nbAttente/(float)MAX_LIST));
		if((nbAttente == 0)&&(etatVidageListe == 1)){
			//envoie d'un XON
			sprintf(ack, "%c", 17);
			for(i = 0;i<nbConn;i++){
				sendto(listenSocket,ack,sizeof(ack),0,(struct sockaddr *) &connectedAddress[i], sizeof(connectedAddress[i]));
			}
			etatReception=1;
			etatVidageListe = 0;
		} else if((((float)nbAttente/(float)MAX_LIST)<0.2f)&&(etatReception == 0)&&(etatVidageListe == 0)){
			//envoie d'un XON
			sprintf(ack, "%c", 17);
			for(i = 0;i<nbConn;i++){
				sendto(listenSocket,ack,sizeof(ack),0,(struct sockaddr *) &connectedAddress[i], sizeof(connectedAddress[i]));
			}
			etatReception=1;
		}
	}
	sleep(1);
	// Envoi de la ligne au serveur
	if (sendto(serverSocket,buffServer, strlen(buffServer), 0, (struct sockaddr *) &serverAddress, sizeof(serverAddress)) < 0) {
		printf("Probleme: ne peut transmettre les donnees.");
		close(serverSocket);
		exit(1);
	}

}

close(serverSocket);
close(listenSocket);

}
//*****************************************
//Fin du Main
//*****************************************



//*****************************************
//Fonction init_ecoute
//A pour but d'initialiser le socket d'ecoute
//*****************************************
int init_ecoute(unsigned short int listenPort){
	int listenSocket, i;
	//unsigned short int listenPort;
	socklen_t clientAddressLength;
	struct sockaddr_in clientAddress, serverAddress;
	char buf[LINE_ARRAY_SIZE];

	memset(buf, 0x0, LINE_ARRAY_SIZE);  // Mise à zéro du tampon

	//printf("Entrez le numero de port d'ecoute (entre 1500 et 65000): ");
	//scanf("%d", &listenPort);
	//listenPort = lPort;

	// Création de socket en écoute et attente des requêtes des clients
	listenSocket = socket(AF_INET, SOCK_DGRAM, 0);
	if (listenSocket < 0) {
		printf("Probleme: ne peut creer le connecteur logique (socket).");
		exit(1);
	}

	// Connexion du socket au port en écoute.
	// On commence par initialiser les champs de la structure serverAddress puis
	// on appelle bind(). Les fonctions htonl() et htons() convertissent
	// respectivement les entiers longs et les entiers courts du rangement hôte
	// (sur x86 on trouve l'octet de poids faible en premier) vers le rangement
	// réseau (octet de poids fort en premier).
	serverAddress.sin_family = AF_INET;
	serverAddress.sin_addr.s_addr = htonl(INADDR_ANY);
	serverAddress.sin_port = htons(listenPort);

	if (bind(listenSocket,(struct sockaddr *) &serverAddress,sizeof(serverAddress)) < 0) {
		printf("Probleme: ne peut etablir une liaison avec le connecteur logique (socket).");
		exit(1);
	}

	// Attente des requêtes clients.
	// C'est un appel non-bloquant ; c'est-à-dire qu'il enregistre ce programme
	// auprès du système comme devant attendre des connexions sur ce socket avec
	// cette tâche. Puis, l'exécution se poursuit.
	listen(listenSocket, 5);

	printf("En attente de requete sur le port %d.\n", listenPort);

	return listenSocket;
	

}
//*****************************************
//Fin de init_ecoute
//*****************************************


//*****************************************
//Fonction init_liste
//A pour but d'initialiser une liste circulaire de MAX_LIST elements
//*****************************************
int init_liste(){
	struct record* noeud;
	head = (struct record*)malloc(sizeof(struct record));
	queue = head;
	int i;
	
	for(i =1;i< MAX_LIST;i++){
		noeud = (struct record*)malloc(sizeof(struct record));
		head->suivant = noeud;
		head = head->suivant;
	}
	
	head->suivant = queue;
	head = head->suivant;
	
	return 0;
}

